//c
#include <unistd.h>
#include <string.h>

//stream
#include <iostream>
#include <sstream>
#include <fstream>

//containers
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <array>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>
#include <string>

//others
#include <algorithm>
#include <numeric>
#include <bitset>
#include <random>

using namespace std;

#include "mGenJson.hpp"
#include "template_fillInputArgs.hpp"

static const string inputfilePos = "input.txt";                 //for custom input thing read
static const string outputfilePos = "output.txt";

static const string inputSubmitfilePos = "inputSubmit.txt";     //for miltiple testcases judge
static const string outputSubmitfilePos = "outputSubmit.txt";   //for miltiple testcases judge

/*
 * read data from file, 
 * input const std::string& fileName
 * return pair<bool, vector<string>>, if OK, first true, second filecontent; else first false, second ""
 */
pair<bool, vector<string>> read_file_to_string(std::string const& fileName)
{
	std::ifstream fin(fileName, std::ios::in);

    if (!fin.is_open()) {
		cout << "fileName:" << fileName << " not found" << endl;
        return {false, {}};
    } else {
		vector<string> res;
		char line[524288] = {0};
		while(fin.getline(line, sizeof(line)))
		{
			string temp = (string)line;
			if (!temp.empty() && temp.back() == 0x0D){
				temp.pop_back();
			}
			res.emplace_back(temp);
		}
		fin.clear();
		fin.close();
		return {true, res};
    }
}

/*
 * create file
 * input string const& fileName,
 * return bool, if OK, true; else false
 */
bool create_file_truncate(string const& fileName){
    std::fstream s;
	s.open(fileName, std::fstream::out|std::fstream::trunc);
    if (!s.is_open()) {
        return false;
    } else {
		s.close();
		return true;
    }
}

/*
 * write data to file
 * input string const& fileName, string const& content
 * return bool, if OK, true; else false
 */
bool write_string_to_file_append(string const& fileName, string const& content)
{
    std::fstream s;
	s.open(fileName, std::fstream::out|std::fstream::app);
    if (!s.is_open()) {
        return false;
    } else {
		s << content;
		s.close();
		return true;
    }
}
class Solution{
public:
	int splitPalindromeMintime(string& raw){
		return 0;
	}
};
/*
 * note: must input with exactedly two para, first shall be a timestamp type
 *    second must be a name with full directory, eq: testproblems/sort/cpp/
 * return code
 *        0x30: OK; 
 *        0x31: para error;
 *        0x32: input file not occured;
 *        0x33: input data not valid/inputSubmit.txt or outputSubmit.txt file not valid or their lines number not matched; 
 *        0x34: output file cannot saved;
 *        1: ADDRESS_SANITIZER_ERROR,         directly catched by cppJudgeSystem parent!
 *        0x35: wrong answer
 *        0x36: debug
 *        the other codes are not predifined, if have other normal exit with exitcode(program normal exit by inside fuction runtime error!, if occur, tell me), in common condition, YOU SHOULD NOT use these not predifined codes here, otherwise confusing question may occur!
 */
int main(int argc, char* argv[]) {
	const int howManyLineOfInputOneCase = 1;
	if (argc != 3){
		return 0x31;
	}else{
		string testId(argv[1]);
		string directory = argv[2];
		string tempOut;
#ifndef submit
		//read data from input.txt, so many data
		pair<bool, vector<string>> readret = read_file_to_string(directory + testId + inputfilePos);
		if (!readret.first){
			return 0x32;
		}
		
		//clear openfile, write input first
		if (!create_file_truncate(directory + testId + outputfilePos)){
			return 0x34;
		}
		if (!write_string_to_file_append(directory + testId + outputfilePos,
		    readret.second[0]
			)){
			return 0x34;
		}
		
		//use JSONlib to decode fileret.second!
		string para1;
		pair<bool, string> ret = m_JSONFrame::fillInputArgs(readret.second, 0, &para1);

		if (!ret.first) return 0x33;  //not valid, how to return the warning datas should be updated in the next version
		
		Solution s = Solution();
		
        int out = s.splitPalindromeMintime(para1);

		//may use JSONlib to encode res!
		mGenJson m = mGenJson(out);
		string JSONres = m.getJSONString();
		
		//write output second
		tempOut += "\ncustomtest&" + JSONres + "&no compare res:(, not implemented yet";
		if (!write_string_to_file_append(directory + testId + outputfilePos,
		    tempOut
			)){  //note: output data split with #, for analyse of client!
			return 0x34;
		}
		
		return 0x30;
#else
		//clear openfile, dump write, for purpose of create empty file; if inputSubmit or outputSubmit txt format error, 
		//    the (cannot read output.txt after execv) error will not be thrown from the caller of cpp judgesystem:)
		if (!create_file_truncate(directory + testId + outputfilePos)){
			return 0x34;
		}

		//read data from inputSubmit/outputSubmit.txt
		pair<bool, vector<string>> readret = read_file_to_string(directory + inputSubmitfilePos);
		pair<bool, vector<string>> oureadret = read_file_to_string(directory + outputSubmitfilePos);
		if (!readret.first || !oureadret.first || (readret.second.size() != oureadret.second.size()*howManyLineOfInputOneCase)){
			return 0x32;
		}
		
		for (int line = 0; line < oureadret.second.size(); line++){
			//clear openfile, write input first
			if (!create_file_truncate(directory + testId + outputfilePos)){
				return 0x34;
			}
			if (!write_string_to_file_append(directory + testId + outputfilePos,
				readret.second[howManyLineOfInputOneCase*line + 0]
				)){
				return 0x34;
			}
			
			//use JSONlib to decode fileret.second!
		    string para1;
			pair<bool, string> ret = m_JSONFrame::fillInputArgs(readret.second, howManyLineOfInputOneCase*line + 0, &para1);

			if (!ret.first) return 0x33;  //not valid, how to return the warning datas should be updated in the next version
			
			Solution s = Solution();
			
            int out = s.splitPalindromeMintime(para1);

			//may use JSONlib to encode res!
			mGenJson m = mGenJson(out);
			string JSONres = m.getJSONString();
			
			if (JSONres != oureadret.second[line]){
				//save output to XXXXoutput.txt
				tempOut += "\ntestcase" + to_string(line) + "&" + JSONres + "&" + oureadret.second[line];
				if (!write_string_to_file_append(directory + testId + outputfilePos,
					tempOut
					)){  //note: output data split with &, for analyse of client!
					return 0x34;
				}
				return 0x35;
			}
		}
		if (!create_file_truncate(directory + testId + outputfilePos)){
			return 0x34;
		}
		tempOut += "AC\npassed all" + to_string(oureadret.second.size()) + " testcases &AC&AC";
		if (!write_string_to_file_append(directory + testId + outputfilePos,
			tempOut
			)){  //note: output data split with &, for analyse of client!
			return 0x34;
		}
		return 0x30;
#endif
	}
}
